package Net::Coro::POP3;
use common::sense;
our $VERSION = 0.03;

use Carp;
use EV;
use Coro;
use Coro::EV;

use Net::Coro::EV::POP3;
use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(async);

use Net::Coro::Proxy;

*BINDIP = \$Net::Coro::EV::POP3::BINDIP;
*TIMEOUT = \$Net::Coro::EV::POP3::TIMEOUT;

sub new {
	my ($class, %prm) = @_;
	my $socket;
	if (ref $prm{socket}) {
		$socket = delete $prm{socket};
	} else {
		$socket = Net::Coro::Proxy->new( delete($prm{socks5}), delete($prm{socks4}), delete($prm{proxy}));
	}
	delete($prm{http_proxy});

	my $this = {};
	bless $this, $class;
	$this->{_POP3} = Net::Coro::EV::POP3->new($socket);
	$this->{_QUIET} = (delete $prm{quiet}) || 0;

	$this->bindip(delete $prm{bindip}) if defined $prm{bindip};
	$this->timeout(delete $prm{timeout}) if defined $prm{timeout};
	$this->timeout_con(delete $prm{timeout_conn}) if defined $prm{timeout_conn};
	
	if (scalar keys %prm) {
		my @prm_names = keys %prm;
		die("unsupported parameter '$prm_names[0]'");
	}
		
	return $this;
}

$EV::DIED = sub {
	print "FATAL ERROR: $@\n";
	print "STACK TRACE: \n";
	foreach (1..5) {
		print join(' ',(caller($_))),"\n";
	}
	exit(1);
};


sub errc {$_[0]->{_POP3}->errc}
sub errm {$_[0]->{_POP3}->errm}

sub callback {
	my ($this, $ftp,  $code, $msg, $data) = @_; 

	delete $this->{_ROUSE_CB};
	if (!defined($code)) {
		if ($this->{_QUIET}) {
			$@ = $this->errm;
			return;
		}
		croak($this->errm);
	}
	
	return wantarray?($code, $msg, $data):$data;
}



sub _rouse_cb {
	my ($this) = @_;
	$this->{_ROUSE_CB} = Coro::rouse_cb;
}

sub DESTROY {
	my ($this) = @_;
	$this->{_POP3}->stop if defined $this->{_POP3}; # check for global destructor
}
# if you want to break connection manually
sub stop {
	my ($this) = @_;
	$this->{_POP3}->stop;
	$this->{_ROUSE_CB}->($this->{_POP3}, undef, "stoped by user", 0) if defined $this->{_ROUSE_CB};
}


#### common methods
sub id {$_[0]->{_POP3}->id($_[1])}
sub socket {$_[0]->{_POP3}->socket}
sub bindip {$_[0]->{_POP3}->bindip($_[1])}
sub timeout {$_[0]->{_POP3}->timeout($_[1])}
sub timeout_conn {$_[0]->{_POP3}->timeout_conn($_[1])}

#### specific methods
sub ssl {$_[0]->{_POP3}->ssl}
sub mcmd {
	my ($this, $command) = @_;
	$this->{_POP3}->mcmd($command, $this->_rouse_cb);
	$this->callback(Coro::rouse_wait);
}
sub cmd {
	my ($this, $command) = @_;
	$this->{_POP3}->cmd($command, $this->_rouse_cb);
	$this->callback(Coro::rouse_wait);
}

sub connect {
	my ($this, $host, $name, $pass) = @_;
	$this->{_POP3}->connect($host, $this->_rouse_cb);
	my ($code, $msg, $data) = $this->callback(Coro::rouse_wait);
	return if !$code;
	
	if ($code eq '-ERR' or ! defined $pass) {
		return wantarray?($code, $msg, $data):$data;
	}
	
	return $this->login($name, $pass);
}

sub login {
	my ($this, $name, $pass) = @_;
	
	$this->{_POP3}->cmd("USER $name", $this->_rouse_cb);
	my ($code, $msg, $data) = $this->callback(Coro::rouse_wait);
	return if !$code;
	if ($code eq '-ERR') {
		return wantarray?($code, $msg, $data):$data;
	}
	
	$this->{_POP3}->cmd("PASS $pass", $this->_rouse_cb);
	return $this->callback(Coro::rouse_wait);
}

sub quit {
	my ($this) = @_;
	$this->{_POP3}->cmd('QUIT', $this->_rouse_cb);
	my ($code, $msg, $data) = $this->callback(Coro::rouse_wait);
	return if !$code;
	
	$this->{_POP3}->stop;
	return wantarray?($code, $msg, $data):$data;
}



sub count {
	my ($this) = @_;
	$this->{_POP3}->cmd('STAT', $this->_rouse_cb);
	my ($code, $msg, $data) = $this->callback(Coro::rouse_wait);
	return if !$code or $code eq '-ERR';
	
	my ($cnt) = $msg =~ /^(\d+)/s;
	return $cnt;
}

sub message {
	my ($this, $index) = @_;
	$index = 1 if !$index;
	$this->{_POP3}->mcmd("RETR $index", $this->_rouse_cb);
	my ($code, $msg, $data) = $this->callback(Coro::rouse_wait);
	return if !$code;	

	if ($code eq '+OK') {
		$this->{_POP3}->cmd("DELE $index", $this->_rouse_cb);
		$this->callback(Coro::rouse_wait);
	} else {
		$data = '';
	}
	return wantarray?($code, $msg, $data):$data;
}
1;